﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.Script.Serialization;
using com.hyrentals.webcommon.filter;
using com.hyrentals.data;
using com.hyrentals.webcommon.extensions;
using com.hyrentals.common;
using com.hyrentals.webcommon.api;
using com.hyrentals.logic;
using System.Globalization;


namespace com.hyrentals.webportal.Controllers
{
    [CustomAuthorize]
    //[OnError(ComponentType.RV)]
    public class RVController : BaseController
    {
        private RVLogic _RVLogic = new RVLogic();
        private AccountLogic _accountLogic = new AccountLogic();
        

        [HttpGet]
        public ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Create(byte type, string modelStyle, string madeYear,
            byte madeBy, string made, byte sleeps, double length,
            string zip, byte availability, bool agree)
        {
            List<object> errorList = new List<object>();

            ViewData.ModelState.Enum("rv_type", type, "Model & Style is required.", typeof(RVTypeEnum));
            ViewData.ModelState.Required("rv_model_style", modelStyle, "Model & Style is required.");
            ViewData.ModelState.MaxLength("rv_model_style", modelStyle, "At most {0} characters.", 100, false);
            ViewData.ModelState.Required("rv_made_year", madeYear, "Year is required.");
            ViewData.ModelState.Year("rv_made_year", madeYear, "Year is unavailable.");
            ViewData.ModelState.Enum("rv_made_by", madeBy, "Made by is required.", typeof(RVMadeByEnum));
            ViewData.ModelState.Range("rv_sleeps", sleeps, 1, 10, "Sleeps must be between {0} and {1}.");
            ViewData.ModelState.Min("rv_length", length, 1, "Length must be more than {} FT.");
            ViewData.ModelState.Required("rv_zip", zip, "zip is required.");
            ViewData.ModelState.Zip("rv_zip", zip, "Please input 5 digit number for zip.");

            int cityId, stateId;
            bool isZipValid = RegionService.ValidateZipCode(zip, out cityId, out stateId);
            if(!isZipValid)
            {
                ViewData.ModelState.AddModelError("rv_zip", "Zip code is invalid, please try another.");
                errorList.Add(new { id = "#rv_zip", msg = "Zip code is invalid, please try another." });
            }

            ViewData.ModelState.Enum("rv_availability", availability, "Availability is required.", typeof(RVAvailabilityTypeEnum));

            if (errorList.Count > 0)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "submit failure, please try again later."
                });
            }

            DateTime year = DateTime.ParseExact(madeYear, "yyyy", CultureInfo.InvariantCulture);
            string newId = Guid.NewGuid().ToString("N");

            if (_RVLogic.InsertRV(newId, User.Identity.Name, (RVTypeEnum)type, modelStyle, year,
                (RVMadeByEnum)madeBy, made, sleeps, length, zip, cityId, stateId, 
                (RVAvailabilityTypeEnum)availability, agree))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = new { redirectUrl = Url.Content("/rvs") }
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "submit failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Pricing(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            return View(rv);
        }

        [HttpPost]
        public ActionResult Pricing(string id, 
            decimal? rentalRateDaily, decimal? rentalRateWeekly, decimal? rentalRateMonthly, 
            int? milageFreeMilesDaily, int? milageFreeMilesWeekly, int? milageFreeMilesMonthly,
            decimal? milagePerExtraMileDaily, decimal? milagePerExtraMileWeekly, decimal? milagePerExtraMileMonthly,
            decimal? depositNonrefundableSecurityDownPayment,
            decimal? depositRefundableDamageProtection,
            decimal? depositRefundableCleaningCharge,
            decimal? LateChargePerHour, ICollection<RVItermizedCharge> itemizedCharges)
        {
            List<object> errorList = new List<object>();

            if (rentalRateDaily != null)
                ViewData.ModelState.MoreThan("rental_rate_daily", (double)rentalRateDaily, 0.0d, "Must be more than {0}.");
            if (rentalRateWeekly != null)
                ViewData.ModelState.MoreThan("rental_rate_weekly", (double)rentalRateWeekly, 0.0d, "Must be more than {0}.");
            if (rentalRateMonthly != null)
                ViewData.ModelState.MoreThan("rental_rate_monthly", (double)rentalRateMonthly, 0.0d, "Must be more than {0}.");
            if (milageFreeMilesDaily != null)
                ViewData.ModelState.MoreThan("milage_free_miles_daily", (double)milageFreeMilesDaily, 0.0d, "Must be more than {0}.");
            if (milageFreeMilesWeekly != null)
                ViewData.ModelState.MoreThan("milage_free_miles_weekly", (double)milageFreeMilesWeekly, 0.0d, "Must be more than {0}.");
            if (milageFreeMilesMonthly != null)
                ViewData.ModelState.MoreThan("milage_free_miles_monthly", (double)milageFreeMilesMonthly, 0.0d, "Must be more than {0}.");
            if (milagePerExtraMileDaily != null)
                ViewData.ModelState.MoreThan("milage_per_extra_mile_daily", (double)milagePerExtraMileDaily, 0.0d, "Must be more than $0}.");
            if (milagePerExtraMileWeekly != null)
                ViewData.ModelState.MoreThan("milage_per_extra_mile_weekly", (double)milagePerExtraMileWeekly, 0.0d, "Must be more than {0}.");
            if (milagePerExtraMileMonthly != null)
                ViewData.ModelState.MoreThan("milage_per_extra_mile_monthly", (double)milagePerExtraMileMonthly, 0.0d, "Must be more than {0}.");
            if (depositNonrefundableSecurityDownPayment != null)
                ViewData.ModelState.MoreThan("deposit_nonrefundable_security_down_payment", (double)depositNonrefundableSecurityDownPayment, 0.0d, "Must be more than {0}.");
            if (depositRefundableDamageProtection != null)
                ViewData.ModelState.MoreThan("deposit_refundable_damage_protection", (double)depositRefundableDamageProtection, 0.0d, "Must be more than {0}.");
            if (depositRefundableCleaningCharge != null)
                ViewData.ModelState.MoreThan("deposit_refundable_cleaning_charge", (double)depositRefundableCleaningCharge, 0.0d, "Must be more than {0}.");
            if (LateChargePerHour != null)
                ViewData.ModelState.MoreThan("late_charge_per_hour", (double)LateChargePerHour, 0.0d, "Must be more than {0}.");
            if (itemizedCharges != null)
            {
                int index = 0;
                foreach (RVItermizedCharge itemizedCharge in itemizedCharges)
                {
                    ++index;
                    ViewData.ModelState.Required("ic_name_" + index, itemizedCharge.Name, "Name is required.");
                    ViewData.ModelState.MaxLength("ic_name_" + index, itemizedCharge.Name, "At most {} characters.", 100, false);
                    ViewData.ModelState.MoreThan("ic_charge_" + index, (double)itemizedCharge.Charge, 0.0d, "Must be more than {0}.");
                } 
            }

            string rentalRateDailyErrMsg = ViewData.ModelState.GetValidationMessage("rental_rate_daily");
            string rentalRateWeeklyErrMsg = ViewData.ModelState.GetValidationMessage("rental_rate_weekly");
            string rentalRateMonthlyErrMsg = ViewData.ModelState.GetValidationMessage("rental_rate_monthly");
            string milageFreeMilesDailyErrMsg = ViewData.ModelState.GetValidationMessage("milage_free_miles_daily");
            string milageFreeMilesWeeklyErrMsg = ViewData.ModelState.GetValidationMessage("milage_free_miles_weekly");
            string milageFreeMilesMonthlyErrMsg = ViewData.ModelState.GetValidationMessage("milage_free_miles_monthly");
            string milagePerExtraMileDailyErrMsg = ViewData.ModelState.GetValidationMessage("milage_per_extra_mile_daily");
            string milagePerExtraMileWeeklyErrMsg = ViewData.ModelState.GetValidationMessage("milage_per_extra_mile_weekly");
            string milagePerExtraMileMonthlyErrMsg = ViewData.ModelState.GetValidationMessage("milage_per_extra_mile_monthly");
            string depositNonrefundableSecurityDownPaymentErrMsg = ViewData.ModelState.GetValidationMessage("deposit_nonrefundable_security_down_payment");
            string depositRefundableDamageProtectionErrMsg = ViewData.ModelState.GetValidationMessage("deposit_refundable_damage_protection");
            string depositRefundableCleaningChargeErrMsg = ViewData.ModelState.GetValidationMessage("deposit_refundable_cleaning_charge");
            string LateChargePerHourErrMsg = ViewData.ModelState.GetValidationMessage("late_charge_per_hour");

            if (rentalRateDailyErrMsg != null)
                errorList.Add(new { id = "#rental_rate_daily", msg = rentalRateDailyErrMsg });
            if (rentalRateWeeklyErrMsg != null)
                errorList.Add(new { id = "#rental_rate_weekly", msg = rentalRateWeeklyErrMsg });
            if (rentalRateMonthlyErrMsg != null)
                errorList.Add(new { id = "#rental_rate_monthly", msg = rentalRateMonthlyErrMsg });
            if (milageFreeMilesDailyErrMsg != null)
                errorList.Add(new { id = "#milage_free_miles_daily", msg = milageFreeMilesDailyErrMsg });
            if (milageFreeMilesWeeklyErrMsg != null)
                errorList.Add(new { id = "#milage_free_miles_weekly", msg = milageFreeMilesWeeklyErrMsg });
            if (milageFreeMilesMonthlyErrMsg != null)
                errorList.Add(new { id = "#milage_free_miles_monthly", msg = milageFreeMilesMonthlyErrMsg });
            if (milagePerExtraMileDailyErrMsg != null)
                errorList.Add(new { id = "#milage_per_extra_mile_daily", msg = milagePerExtraMileDailyErrMsg });
            if (milagePerExtraMileWeeklyErrMsg != null)
                errorList.Add(new { id = "#milage_per_extra_mile_weekly", msg = milagePerExtraMileWeeklyErrMsg });
            if (milagePerExtraMileMonthlyErrMsg != null)
                errorList.Add(new { id = "#milage_per_extra_mile_monthly", msg = milagePerExtraMileMonthlyErrMsg });
            if (depositNonrefundableSecurityDownPaymentErrMsg != null)
                errorList.Add(new { id = "#deposit_nonrefundable_security_down_payment", msg = depositNonrefundableSecurityDownPaymentErrMsg });
            if (depositRefundableDamageProtectionErrMsg != null)
                errorList.Add(new { id = "#deposit_refundable_damage_protection", msg = depositRefundableDamageProtectionErrMsg });
            if (depositRefundableCleaningChargeErrMsg != null)
                errorList.Add(new { id = "#deposit_refundable_cleaning_charge", msg = depositRefundableCleaningChargeErrMsg });
            if (LateChargePerHourErrMsg != null)
                errorList.Add(new { id = "#late_charge_per_hour", msg = LateChargePerHourErrMsg });

            if (errorList.Count > 0)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "submit failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            if (_RVLogic.SavePricing(id,
                rentalRateDaily, rentalRateWeekly, rentalRateMonthly,
                milageFreeMilesDaily, milageFreeMilesWeekly, milageFreeMilesMonthly,
                milagePerExtraMileDaily, milagePerExtraMileWeekly, milagePerExtraMileMonthly,
                depositNonrefundableSecurityDownPayment,
                depositRefundableDamageProtection,
                depositRefundableCleaningCharge,
                LateChargePerHour, itemizedCharges))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = "Save successfully."
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Overview(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            return View(rv);
        }

        [HttpPost]
        public ActionResult Overview(string id, string title, string summary, byte type,
            string modelStyle, string madeYear, byte madeBy, string made, bool agree)
        {
            ViewData.ModelState.MaxLength("title", title, "At most {} characters.", 50, false);
            ViewData.ModelState.MaxLength("summary", summary, "At most {} characters.", 200, false);
            ViewData.ModelState.Enum("type", type, "Model & Style is required.", typeof(RVTypeEnum));
            ViewData.ModelState.Required("model_style", modelStyle, "Model & Style is required.");
            ViewData.ModelState.MaxLength("model_style", modelStyle, "At most {0} characters.", 100, false);
            ViewData.ModelState.Required("made_year", madeYear, "Year is required.");
            ViewData.ModelState.Year("made_year", madeYear, "Year is unavailable.");
            ViewData.ModelState.Enum("made_by", madeBy, "Made by is required.", typeof(RVMadeByEnum));

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
            DateTime year = DateTime.ParseExact(madeYear, "yyyy", CultureInfo.InvariantCulture);
            if (_RVLogic.SaveOverview(id, title, summary, type, modelStyle, year, madeBy, made, agree))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = "Save successfully."
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Address(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            return View(rv);
        }

        [HttpPost]
        public ActionResult Address(string id, string zip, string address)
        {
            List<object> errorList = new List<object>();

            ViewData.ModelState.Required("rv_id", id, "Id is required.");
            ViewData.ModelState.Required("rv_zip", zip, "zip is required.");
            ViewData.ModelState.Zip("rv_zip", zip, "Please input 5 digit number for zip.");
            
            int cityId, stateId;
            bool isZipValid = RegionService.ValidateZipCode(zip, out cityId, out stateId);
            if (!isZipValid)
            {
                ViewData.ModelState.AddModelError("rv_zip", "Zip code is invalid, please try another.");
            }

            ViewData.ModelState.MaxLength("rv_address", address, "At most {0} characters.", 200, false);

            if (!ViewData.ModelState.IsValid)
            {
                errorList = ViewData.ModelState.GenerateErrorList();
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            if (_RVLogic.SaveAddress(rv.Id, zip, address))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = "Save successfully."
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Automotive(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            return View(rv);
        }

        [HttpPost]
        public ActionResult Automotive(string id, string[] basicFeatures, byte? overdriveTrans,
            string[] electricalFeatures, byte? engineType, double? fuelConsumption,
            string chassis, double? grossWeight, double? tongueWeight)
        {
            
            List<object> errorList = new List<object>();

            if (basicFeatures != null)
            {
                foreach (string basicFeature in basicFeatures)
                {
                    ViewData.ModelState.Enum("basic_feature", basicFeature, "Basic features selected is invalid.", typeof(RVAutomotiveBasicFeatureEnum));
                }
            }

            if (overdriveTrans != null)
            {
                ViewData.ModelState.Enum("overdrive_trans", (byte)overdriveTrans, "Overdrive Transmission selected is invalid." , typeof(RVOverdriveTransmissionEnum));
            }

            if (electricalFeatures != null)
            {
                foreach (string electricalFeature in electricalFeatures)
                {
                    ViewData.ModelState.Enum("electrical_feature", electricalFeature, "Electrical features selected is invalid.", typeof(RVAutomotiveElectricalFeatureEnum));
                }
            }

            if (engineType != null)
            {
                ViewData.ModelState.Enum("engine_type", (byte)engineType, "Engine type selected is invalid.", typeof(RVAutomotiveEngineTypeEnum));
            }

            if (fuelConsumption != null)
            {
                ViewData.ModelState.Min("fuel_consumption", (double)fuelConsumption, 0, "Fuel consumption must be equal or more than {} L.");
            }

            if (grossWeight != null)
            {
                ViewData.ModelState.Min("gross_weight", (double)grossWeight, 0, "Gross weidht must be equal or more than {} L.");
            }

            if (tongueWeight != null)
            {
                ViewData.ModelState.Min("tongue_weight", (double)tongueWeight, 0, "Tongue weight must be equal or more than {} L.");
            }

            string fuelConsumptionErrMsg = ViewData.ModelState.GetValidationMessage("fuel_consumption");
            string grossWeightErrMsg = ViewData.ModelState.GetValidationMessage("gross_weight");
            string tongueWeightErrMsg = ViewData.ModelState.GetValidationMessage("tongue_weight");

            if(fuelConsumptionErrMsg != null)
                errorList.Add(new { id = "#fuel_consumption", msg = fuelConsumptionErrMsg });
            if (grossWeightErrMsg != null)
                errorList.Add(new { id = "#gross_weight", msg = grossWeightErrMsg });
            if (tongueWeightErrMsg != null)
                errorList.Add(new { id = "#tongue_weight", msg = tongueWeightErrMsg });

            if (errorList.Count > 0)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            byte[] basicFeatureBytes = null;
            if (basicFeatures != null)
            {
                basicFeatureBytes = new byte[basicFeatures.Length];
                for (int i = 0; i < basicFeatures.Length; ++i)
                {
                    basicFeatureBytes[i] = byte.Parse(basicFeatures[i]);
                }
            }

            byte[] electricalFeatureBytes = null;
            if (electricalFeatures != null)
            {
                electricalFeatureBytes = new byte[electricalFeatures.Length];
                for (int i = 0; i < electricalFeatures.Length; ++i)
                {
                    electricalFeatureBytes[i] = byte.Parse(electricalFeatures[i]);
                }
            }

            if (_RVLogic.SaveAutomotive(id, basicFeatureBytes, overdriveTrans,
                electricalFeatureBytes, engineType, fuelConsumption,
                chassis, grossWeight, tongueWeight))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = "Save successfully."
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Interior(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            return View(rv);
        }

        [HttpPost]
        public ActionResult Interior(string id, byte sleeps, double? width, double? length,
            double? blackWaterTank, double? greyWaterTank, double? freshWaterTank,
            double? waterHeater, double? propaneTanks, string[] kitchBathroomFeatures,
            string[] bedFeatures)
        {

            List<object> errorList = new List<object>();

            ViewData.ModelState.Range("sleeps", sleeps, 1, 10, "Sleeps must be between {0} and {1}.");
            if (width != null)
            {
                ViewData.ModelState.MoreThan("width", (double)width, 0.0d, "Must be more than {0} FT.");
            }
            if (length != null)
            {
                ViewData.ModelState.MoreThan("length", (double)length, 0.0d, "Must be more than {0} FT.");
            }
            if (blackWaterTank != null)
            {
                ViewData.ModelState.MoreThan("black_water_tank", (double)blackWaterTank, 0.0d, "Must be more than {0} FT.");
            }
            if (greyWaterTank != null)
            {
                ViewData.ModelState.MoreThan("grey_water_tank", (double)greyWaterTank, 0.0d, "Must be more than {0} FT.");
            }
            if (freshWaterTank != null)
            {
                ViewData.ModelState.MoreThan("fresh_water_tank", (double)freshWaterTank, 0.0d, "Must be more than {0} FT.");
            }
            if (waterHeater != null)
            {
                ViewData.ModelState.MoreThan("water_heater", (double)waterHeater, 0.0d, "Must be more than {0} FT.");
            }
            if (propaneTanks != null)
            {
                ViewData.ModelState.MoreThan("propane_tanks", (double)propaneTanks, 0.0d, "Must be more than {0} FT.");
            }

            if (kitchBathroomFeatures != null)
            {
                foreach (string kitchBathroomFeature in kitchBathroomFeatures)
                {
                    ViewData.ModelState.Enum("kitch_bath", kitchBathroomFeature, "Kitch Bathroom features selected is invalid.", typeof(RVInteriorKitchBathroomFeatureEnum));
                }
            }

            if (bedFeatures != null)
            {
                foreach (string bedFeature in bedFeatures)
                {
                    ViewData.ModelState.Enum("bed", bedFeature, "Bed features selected is invalid.", typeof(RVInteriorBedFeatureEnum));
                }
            }

            string sleepsErrMsg = ViewData.ModelState.GetValidationMessage("sleeps");
            string widthErrMsg = ViewData.ModelState.GetValidationMessage("width");
            string lengthWeightErrMsg = ViewData.ModelState.GetValidationMessage("length");
            string blackWaterTankErrMsg = ViewData.ModelState.GetValidationMessage("black_water_tank");
            string greyWaterTankErrMsg = ViewData.ModelState.GetValidationMessage("grey_water_tank");
            string freshWaterTankErrMsg = ViewData.ModelState.GetValidationMessage("fresh_water_tank");
            string waterHeaterErrMsg = ViewData.ModelState.GetValidationMessage("water_heater");
            string propaneTanksErrMsg = ViewData.ModelState.GetValidationMessage("propane_tanks");

            if (sleepsErrMsg != null)
                errorList.Add(new { id = "#sleeps", msg = sleepsErrMsg });
            if (widthErrMsg != null)
                errorList.Add(new { id = "#width", msg = widthErrMsg });
            if (lengthWeightErrMsg != null)
                errorList.Add(new { id = "#length", msg = lengthWeightErrMsg });
            if (blackWaterTankErrMsg != null)
                errorList.Add(new { id = "#black_water_tank", msg = blackWaterTankErrMsg });
            if (greyWaterTankErrMsg != null)
                errorList.Add(new { id = "#grey_water_tank", msg = greyWaterTankErrMsg });
            if (freshWaterTankErrMsg != null)
                errorList.Add(new { id = "#fresh_water_tank", msg = freshWaterTankErrMsg });
            if (waterHeaterErrMsg != null)
                errorList.Add(new { id = "#water_heater", msg = waterHeaterErrMsg });
            if (propaneTanksErrMsg != null)
                errorList.Add(new { id = "#propane_tanks", msg = propaneTanksErrMsg });


            if (errorList.Count > 0)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            byte[] kitchBathroomFeatureBytes = null;
            if (kitchBathroomFeatures != null)
            {
                kitchBathroomFeatureBytes = new byte[kitchBathroomFeatures.Length];
                for (int i = 0; i < kitchBathroomFeatures.Length; ++i)
                {
                    kitchBathroomFeatureBytes[i] = byte.Parse(kitchBathroomFeatures[i]);
                }
            }

            byte[] bedFeatureBytes = null;
            if (bedFeatures != null)
            {
                bedFeatureBytes = new byte[bedFeatures.Length];
                for (int i = 0; i < bedFeatures.Length; ++i)
                {
                    bedFeatureBytes[i] = byte.Parse(bedFeatures[i]);
                }
            }

            if (_RVLogic.SaveInterior(id, sleeps, width, length, blackWaterTank,
                greyWaterTank, freshWaterTank, waterHeater, propaneTanks,
                kitchBathroomFeatureBytes, bedFeatureBytes))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = "Save successfully."
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Calendar(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            return View(rv);
        }

        [HttpPost]
        public ActionResult Calendar(string id, byte availability, ICollection<RVAvailableDateInterval> dateIntervals)
        {
            ViewData.ModelState.Enum("availability", availability, "Availability selected is invalid.", typeof(RVAvailabilityTypeEnum));
            
            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            RVAvailabilityTypeEnum availableType = (RVAvailabilityTypeEnum)availability;


            if (_RVLogic.SaveCalendar(id, availableType, dateIntervals))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = "Save successfully."
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "submit failure, please try again later."
                });
            }
        }

        [HttpPost]
        public ActionResult Photo(string photoId, string RVId)
        {
            ViewData.ModelState.Required("photo_id", photoId, "Photo Id is required.");
            ViewData.ModelState.Required("rv_id", RVId, "RV Id is required.");

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(RVId, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }

            Photo photo = new Photo
            {
                Id = photoId,
                RVId = RVId,
                CreatTime = DateTime.UtcNow
            };

            if (_RVLogic.SavePhoto(photo))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = this.RenderPartialViewToString("w_Photo", photo)
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Save failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult Photos(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("NotFound", "Error");
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(id, User.Identity.Name);
            if (rv == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            IEnumerable<Photo> photos = _RVLogic.GetPhotoByRVId(rv.Id);

            ViewBag.Photos = photos;
            return View(rv);
        }

        [HttpPost]
        public ActionResult DeletePhoto(string photoId, string RVId)
        {
            ViewData.ModelState.Required("photo_id", photoId, "Photo Id is required.");
            ViewData.ModelState.Required("rv_id", RVId, "RV Id is required.");

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Delete failure, please try again later."
                });
            }

            RV rv = _RVLogic.GetRVByIdAndOwnerId(RVId, User.Identity.Name);
            if (rv == null)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Delete failure, please try again later."
                });
            }

            if (_RVLogic.DeletePhoto(photoId, rv.Id))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = string.Empty
                   });
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Delete failure, please try again later."
                });
            }
        }

        [HttpGet]
        public ActionResult UpdatePhoto(string photoId, string RVId, string description)
        {
            ViewData.ModelState.Required("photo_id", photoId, "Photo Id is required.");
            ViewData.ModelState.Required("rv_id", RVId, "RV Id is required.");

            if (!ViewData.ModelState.IsValid)
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Update failure, please try again later."
                }, JsonRequestBehavior.AllowGet);
            }

            if (_RVLogic.UpdatePhoto(User.Identity.Name, photoId, RVId, description))
            {
                return Json(
                   new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = string.Empty
                   }, JsonRequestBehavior.AllowGet);
            }
            else
            {
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = "Update failure, please try again later."
                }, JsonRequestBehavior.AllowGet);
            }
        }

        [HttpPost]
        public ActionResult Book(string RVId, string checkin, string checkout)
        {
            ViewData.ModelState.Required("msg_checkin", checkin, "Checkin is required.");
            ViewData.ModelState.Required("msg_checkout", checkout, "Checkout is required.");
            ViewData.ModelState.Date("msg_checkin", checkin, "Invalid checkin.");
            ViewData.ModelState.Date("msg_checkout", checkout, "Invalid checkout.");
            DateTime checkinTime = DateTime.ParseExact(checkin, "yyyy-MM-dd", CultureInfo.InvariantCulture);
            DateTime checkoutTime = DateTime.ParseExact(checkout, "yyyy-MM-dd", CultureInfo.InvariantCulture);
            if (checkinTime > checkoutTime)
            {
                ViewData.ModelState.AddModelError("msg_summary", "Check in must be larger than Check out.");
            }

            List<object> errorList = new List<object>();
            if (!ViewData.ModelState.IsValid)
            {
                errorList = ViewData.ModelState.GenerateErrorList();
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            string userId = User.Identity.Name;
            RV rv = _RVLogic.GetRVById(RVId);
            if (rv == null)
            {
                errorList.Add(new { id = "msg_summary", msg = "RV is not existed." });
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            if (rv.OwnerId == userId)
            {
                errorList.Add(new { id = "msg_summary", msg = "Booking your own RV is not allowed." });
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            if (!rv.IsBookReady())
            {
                errorList.Add(new { id = "msg_summary", msg = "This RV is not ready to be booked." });
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }

            RentalRequestLogic rentalRequestLogic = new RentalRequestLogic();
            if (rentalRequestLogic.InsertRentalRequest(rv, userId, checkinTime, checkoutTime))
            {
                return Json(new JsonResultObj
                   {
                       Result = ResultStatusCode.Success,
                       Content = string.Empty
                   });
            }
            else
            {
                errorList.Add(new { id = "msg_summary", msg = "Book failure, please try again later." });
                return Json(new JsonResultObj
                {
                    Result = ResultStatusCode.Error,
                    Content = errorList
                });
            }
        }
    }

    public class DateIntervalObj
    {
        public string StartDate { get; set; }
        public string EndDate { get; set; }
    }
}